package com.javaxiaobang.counter.aspect.log;

import com.javaxiaobang.counter.util.LogCounterUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 功    能：远程计数器-调用远程服务保存数据
 * 作    者：java潇邦
 * 时    间：2018-05-19
 */
@Component("logCounterRemoteBusiness")
public class LogCounterRemoteBusiness {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static ReentrantLock lock = new ReentrantLock();

    private static String domain = LogCounterUtil.getDomain();

    private static long tryLockTime = 2;//尝试2秒获取锁的时间

    private static long refreshTime = 30000L;//30秒刷新一次

    private static ConcurrentHashMap<String, AtomicLong> countMap = new ConcurrentHashMap<String, AtomicLong>(32);//并发计数

    private static ConcurrentHashMap<String, Long> timeMap = new ConcurrentHashMap<String, Long>(32);//并发计时

    private static long detailRefreshTime = 10 * 60 * 1000L;//默认10分钟刷新数据

    private static ConcurrentHashMap<String, AtomicLong> detailCountMap = new ConcurrentHashMap<String, AtomicLong>(32);//并发计数

    private static ConcurrentHashMap<String, Long> detailTimeMap = new ConcurrentHashMap<String, Long>(32);//并发计时

//    private CounterServiceHelper.CounterServiceClient client = new CounterServiceHelper.CounterServiceClient();//唯品会counter服务-对应两张表

    /**
     * 计数器逻辑处理
     */
    public void execute(String counterName) {
        commonMethod("total", counterName, refreshTime, countMap, timeMap);//计数器头表
        commonMethod("detail", counterName, detailRefreshTime, detailCountMap, detailTimeMap);//计数器明细表
    }

    private void commonMethod(String type, String counterName, long refreshTime, ConcurrentHashMap<String, AtomicLong> countMap, ConcurrentHashMap<String, Long> timeMap) {
        try {
            String key = counterName + domain;//唯一key
            AtomicLong atomicLong = countMap.get(key);
            if (null == atomicLong) {//原子计数器
                synchronized (lock) {//并发控制
                    atomicLong = countMap.get(key);
                    if (null == atomicLong) {
                        countMap.put(key, new AtomicLong(1));
                        timeMap.put(key, System.currentTimeMillis());
                        return;
                    }
                }
            }
            atomicLong.incrementAndGet();//原子计数器加1

            boolean flag = (System.currentTimeMillis() - timeMap.get(key) > refreshTime) && (atomicLong.get() > 0);//超过N秒 并且 次数大于0
            if (flag) {//满足条件的漏斗
                if (lock.tryLock(tryLockTime, TimeUnit.SECONDS)) {
                    try {
                        flag = (System.currentTimeMillis() - timeMap.get(key) > refreshTime) && (atomicLong.get() > 0);//避免错误更新
                        if (flag) {
                            long counter = countMap.get(key).get();
                            timeMap.put(key, System.currentTimeMillis());//重新计时
                            atomicLong.set(0);
                            countMap.put(key, atomicLong);//重新计数
                            if ("detail".equals(type)) {
                                incrementDetailCounter(counterName, domain, counter, refreshTime);
                            } else {
                                incrementCounter(counterName, domain, counter);
                            }
                        }
                    } finally {
                        lock.unlock();
                    }
                } else {
                    logger.warn("2秒内没有获取到锁则放弃,下次再调用远程保存数据的服务:{}", key);
                }
            }
        } catch (Exception e) {
            logger.debug("remote计数器异常:", e);
        }
    }

    /**
     * 保存到counter_info头表
     */
    public void incrementCounter(String counterName, String domain, long counter) {
        //调用远程方法
//        try {
//            CounterInfo counterInfo = new CounterInfo();
//            counterInfo.setCounterName(counterName);
//            counterInfo.setDomain(domain);
//            counterInfo.setCounter(counter);
//            client.incrementCounter(counterInfo);
//        } catch (Exception e) {
//            logger.debug("incrementCounter:", e);
//        }
    }

    /**
     * 保存到counter_detail明细表
     */
    public void incrementDetailCounter(String counterName, String domain, long counter, long interval) {
        //调用远程方法
//        try {
//            CounterInfo counterInfo = new CounterInfo();
//            counterInfo.setCounterName(counterName);
//            counterInfo.setDomain(domain);
//            counterInfo.setCounter(counter);
//            counterInfo.setInterval(interval);
//            client.incrementDetailCounter(counterInfo);
//        } catch (Exception e) {
//            logger.debug("incrementDetailCounter:", e);
//        }
    }

    public static long getRefreshTime() {
        return refreshTime;
    }

    public static void setRefreshTime(long refreshTime) {
        LogCounterRemoteBusiness.refreshTime = refreshTime;
    }

    public static long getDetailRefreshTime() {
        return detailRefreshTime;
    }

    public static void setDetailRefreshTime(long detailRefreshTime) {
        LogCounterRemoteBusiness.detailRefreshTime = detailRefreshTime;
    }

    public static void setDomain(String domain) {
        LogCounterRemoteBusiness.domain = domain;
    }

    public static String getDomain() {
        return domain;
    }


}
